package env

import (
	"fmt"
	"os"
	"strings"

	"gitee.com/go-errors/errors"
	"github.com/segmentio/go-snakecase"
	"gopkg.in/yaml.v2"
)

func Auto() {
	fns := []string{".env", ".env", "env.yml", ".env.yml"}
	if fm, err := Flatten(fns...); err == nil {
		for k, v := range fm {
			setEnv(k, v)
		}
	}
}

func setEnv(k, v string) {
	if v != "" {
		if n := strings.ToUpper(snakecase.Snakecase(k)); n != k {
			_ = os.Setenv(n, v)
		}
		_ = os.Setenv(k, v)
	}
}

func Flatten(fns ...string) (map[string]string, error) {
	var me error
	m := map[string]string{}
	for _, fn := range fns {
		if err := flatten(&m, fn); err != nil {
			me = errors.Multi(me, err)
		}
	}
	return m, me
}

func flatten(ms *map[string]string, fn string) error {
	var (
		v   []byte
		err error
	)

	v, err = os.ReadFile(fn)
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return errors.Wrap(err)
	}

	mv := map[interface{}]interface{}{}
	if err := yaml.Unmarshal(v, &mv); err != nil {
		return errors.Wrap(err)
	}

	flattenMap("", mv, ms)

	return nil
}

func flattenValue(key string, value interface{}, ms *map[string]string) {
	key = strings.Trim(key, " .")
	switch st := value.(type) {
	case map[interface{}]interface{}:
		flattenMap(key, st, ms)
	case []interface{}:
		flattenList(key, st, ms)
	default:
		(*ms)[key] = fmt.Sprintf("%v", st)
	}
}

func flattenMap(key string, mv map[interface{}]interface{}, ms *map[string]string) {
	for i, value := range mv {
		flattenValue(fmt.Sprintf("%s.%s", key, i), value, ms)
	}
}

func flattenList(key string, ml []interface{}, ms *map[string]string) {
	for i, value := range ml {
		flattenValue(fmt.Sprintf("%s[%d]", key, i), value, ms)
	}
}
